###############################################################################################################
#   Author:Robert Baron
#   Date:  08/08/2012
#   Version 0.1
#
#   #############   #############    ## 
#   ##              ##               ##
#   ##              ##
#   ##              #############    ##
#   ##     ######              ##    ##
#   ##         ##   ##         ##    ##
#   ##         ##   ##         ##    ##
#   #############   #############    ## 
#   gsicr-scanner is a small tool that allows a single scan of a particular host,
#   attempts a connection to a given port, if the connection is successful the result shows
#
#   Usage:
#   python gsicr-scanner.py -a [host] [options]
###############################################################################################################

import socket, sys 
from optparse import OptionParser

#hash table with different states resulting from the connection.
status={0:"Open",10049:"Address not available",10061:"Closed",10060:"Timeout",10056:"Already connected",10035:"Filtered",11001:"IP not found",10013:"Permission denied"}
#Default port list
ports={80:"Http", 23:"", 443:"SSL", 21:"FTP", 22:"SSH", 25:"SMTP", 3389:"", 110:"POP3", 445:"", 139:"", 143:"", 53:"", 135:"", 3306:"MYSQL", 8080:"HTTP", 1723:"", 111:"", 995:"", 993:"", 5900:"", 1025:"", 587:"", 8888:"", 199:"", 1720:"", 465:"", 548:"", 113:"", 81:"", 6001:"", 10000:"", 514:"", 5060:"", 179:"", 1026:"", 2000:"", 8443:"", 8000:"", 32768:"", 554:"", 26:"", 1433:"", 49152:"", 2001:"", 515:"", 8008:"", 49154:"", 1027:"", 5666:"", 646:"", 5000:"", 5631:"", 631:"", 49153:"", 8081:"", 2049:"", 88:"", 79:"", 5800:"", 106:"", 2121:"", 1110:"", 49155:"", 6000:"", 513:"", 990:"", 5357:"", 427:"", 49156:"", 543:"", 544:"", 5101:"", 144:"", 7:"", 389:"", 8009:"", 3128:"", 444:"", 9999:"", 5009:"", 7070:"", 5190:"", 3000:"", 5432:""}

#Verbose?
verbose = False

#HostName?
host = False

#Contains information of open ports
output = "Port\t\tState\t\tService\n"
def scan(address, port,timeout):
    global output
    #Get socket
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #Set timeout
    s.settimeout(timeout)
    #If in verbose mode the program's actions
    if verbose == 'True':
        print "Attempting to connect %s on port %s." %(address, port) 
    try:
        #Tries to connect, and get the result
        result = s.connect_ex((address, port))

        #If in verbose mode the program's actions
        if verbose == 'True':
            #iI the result is zero means that the connection successfully performed and the port is open
            if(result == 0):
                output += "%s\t\t%s\t\t%s\n" %(port,status[result],socket.getservbyport(port))
                print "%s %s %s" %(port,status[result],socket.getservbyport(port))
            else:
                output += "%s\t\t%s\t\t%s\n" %(port,status[result],"")
                print "%s %s" %(port,status[result])
        #Si se solicito que obtenga el nombre del host
        if host == 'True':
            print "HostName: %s" %(socket.gethostbyaddr(address)[0])
        #Close connection.
        s.close()
        return True 
    except socket.error, e: 
        print "Connection failed: %s" %(e) 
        return False 

if __name__ == '__main__':
    print 'Initializing GSICR-scanner...\n'
    #Script options
    parser = OptionParser() 
    parser.add_option("-a", "--address", dest="address", default="localhost", metavar="ADDRESS", help="Direccion del servidor" ) 
    parser.add_option("-p", "--port",    dest="port",    default ="default",  metavar="PORT",    help="Puerto del servidor"  )
    parser.add_option("-v", "--verbose", dest="verbose", default="True",      metavar="VERBOSE", help="Muestra informacion sobre acciones del script. Para desactivarlo -v False")
    parser.add_option("-t", "--timeout", dest="timeout", default=10,          metavar="TIMEOUT", help="Timeout del socket")
    parser.add_option("-n", "--name",    dest="host",    default="False",     metavar="HOST",    help="Nombre del host")
    (options, args) = parser.parse_args()

    verbose = options.verbose
    host    = options.host 
    
    #If in verbose mode the program's actions
    if verbose == 'True':
        print 'Options: %s, args: %s' %(options, args)
        
    #Verificamos la opcion -p    
    if options.port == 'default':
        #En caso que no se halla especificado ningun puerto en especifico, recorre una lista predeterminada de puertos
        for key in ports.keys():
            #If in verbose mode the program's actions
            if verbose == 'True':
                print '\nChecking \tport %s on %s...' %(key, options.address) 
            scan(options.address, key,int(options.timeout))             
    else: 
        options.port = int(options.port)
        #If in verbose mode the program's actions
        if verbose == 'True':
            print '\nChecking port %s on %s...' %(options.port, options.address) 
        scan(options.address, options.port,int(options.timeout))
    print '\n'
    print output
    print "\nScan complete!"
